# coding:UTF-8
# 导入需要的库
import sys, pygame, random
from pygame.locals import *

# 基础初始化操作
# Pygame游戏库初始化
pygame.init()
# 创建时钟对象 (可以控制游戏循环频率)
clock = pygame.time.Clock()
# 控制重复响应持续按下按键的时间，10毫秒以上
pygame.key.set_repeat(10)
# 设置窗口标题
pygame.display.set_caption("贪吃蛇")
windowWidth = 600
windowHeight = 600
cellSize = 20
# 创建显示窗口
screen = pygame.display.set_mode((windowWidth, windowHeight))
screen.fill([129, 216, 208])  
# 资源导入
#颜色色号：覆盆子红RGB 158/46/36虎皮黄 RGB 226/175/66薄荷绿 RGB 64/125/82草黄 RGB 207/182/74星蓝 RGB： 154/180/205鸢尾蓝 RGB： 65/138/180苋菜紫 RGB： 142/41/97钢蓝 RGB： 16/20/32云峰白 RGB： 218/227/230岩石棕RGB： 140/80/44橄榄石绿 RGB： 184/206/142竹绿 RGB: 79/164/133钴蓝 RGB:  70/146/185月影白 RGB：194/196/195笋皮棕 RGB：107/51/26

# 定义各种类
# 定义贪吃蛇类
class Snack():
    def __init__(self):
        self.body = []  # 记录全部顶点
        self.newHead_x = 0
        self.newHead_y = 0
        self.add = 0  #还需增加的长度
        self.move_direction = 3  # 0123，分别代表上左右下
        self.turn_direction = 3  # 0123，分别代表上左右下
        self.color = Color(218, 227, 230)
    # 在屏幕上画出自己
    def draw(self):
        # pygame.draw.rect(surface,color,Rect,width=0) 画一个矩形
        for point in self.body:
            pygame.draw.rect(screen, self.color,
                             (point[0], point[1], cellSize, cellSize))
    # 随机出生
    def born(self):
        self.body = []
        x = cellSize*random.randint(8, windowWidth/cellSize-8)
        y = cellSize*random.randint(8, windowHeight/cellSize-8)
        for i in range(3):
            AllVar.allPoints.append([x, y - i*cellSize])
            self.body.append([x, y - i*cellSize])
            
    # 根据方向计算新头坐标
    def newHead(self, direction):
        if direction == 0:  # 向上
            self.newHead_x = self.body[0][0]
            self.newHead_y = self.body[0][1] - cellSize
            if self.body[0][1] == 0:  # 穿墙
                self.newHead_y = cellSize*(windowHeight/cellSize - 1)
        elif direction == 1:  # 向左
            self.newHead_x = self.body[0][0] - cellSize
            self.newHead_y = self.body[0][1]
            if self.body[0][0] == 0:
                self.newHead_x = cellSize*(windowHeight/cellSize - 1)
        elif direction == 2:  # 向右
            self.newHead_x = self.body[0][0] + cellSize
            self.newHead_y = self.body[0][1]
            if self.body[0][0] == cellSize*(windowHeight/cellSize - 1):
                self.newHead_x = 0
        elif direction == 3:  # 向下
            self.newHead_x = self.body[0][0]
            self.newHead_y = self.body[0][1] + cellSize
            if self.body[0][1] == cellSize*(windowHeight/cellSize - 1):
                self.newHead_y = 0

    # 默认坚持之前移动方向，最后一块消失，新增第一块
    def move(self):
        self.newHead(self.move_direction)
        if self.eatObject(AllVar.apple):  #如果吃到苹果，则增加头部，不删除尾巴即可
            AllVar.score += len(AllVar.apple.body)
            addRandomWall()
            AllVar.level = AllVar.score // 5
            self.body.insert(0, [self.newHead_x, self.newHead_y])
            AllVar.apple.born()
            return
        if self.eatObject(AllVar.long):  #如果吃到变长道具，则身子扩展成2倍长度，尾巴不见头一直增加
            self.add = len(self.body)
            AllVar.long.born()
            return
        if self.eatObject(AllVar.appleBig):  #如果吃到苹果变大道具，则苹果大成2倍
            point1 = [AllVar.apple.body[0][0]+cellSize, AllVar.apple.body[0][1]]
            point2 = [AllVar.apple.body[0][0], AllVar.apple.body[0][1]+cellSize]
            point3 = [AllVar.apple.body[0][0]+cellSize, AllVar.apple.body[0][1]+cellSize]
            if not checkOverlapping(point1) and not checkOverlapping(point2) and not checkOverlapping(point3):
                AllVar.apple.body.append(point1)
                AllVar.apple.body.append(point2)
                AllVar.apple.body.append(point3)
                AllVar.allPoints.append(point1)
                AllVar.allPoints.append(point2)
                AllVar.allPoints.append(point3)
            AllVar.appleBig.born()
            return
        if self.eatObject(AllVar.snake) or self.eatObject(AllVar.wall):  #如果吃到自身，则游戏结束
            AllVar.state = 'end'
            return
        if self.eatObject(AllVar.addWall):   #如果吃到变墙，则四周变成墙
            for x in range(0, windowWidth, cellSize):
                AllVar.wall.body.append([x,0])
                AllVar.allPoints.append([x,0])
            for x in range(0, windowWidth, cellSize):
                AllVar.wall.body.append([x,windowHeight-cellSize])
                AllVar.allPoints.append([x,windowHeight-cellSize])
            for y in range(0, windowHeight, cellSize):
                AllVar.wall.body.append([0,y])
                AllVar.allPoints.append([0,y])
            for y in range(0, windowHeight, cellSize):
                AllVar.wall.body.append([windowWidth-cellSize, y])
                AllVar.allPoints.append([windowWidth-cellSize, y])
            AllVar.addWall.body = []
            return
        if self.add > 0: #说明还有需要增加的长度，则不删除尾巴
            self.body.insert(0, [self.newHead_x, self.newHead_y])
            AllVar.allPoints.append([self.newHead_x, self.newHead_y])
            self.add -= 1
            return
        AllVar.allPoints.remove(self.body[-1])
        self.body.pop(-1)
        self.body.insert(0, [self.newHead_x, self.newHead_y])
        AllVar.allPoints.append([self.newHead_x, self.newHead_y])

    # 转向，修改生成新头的方向
    def turn(self, direction):
        if self.move_direction + direction != 3:
            self.move_direction = direction
    # 吃到道具
    def eatObject(self, object):
        for point in object.body:
            if self.newHead_x == point[0] and self.newHead_y == point[1]:
                return True
        return False

# 定义游戏道具类，它是全部道具类的父亲
class GameProps():
    def __init__(self):
        self.body = []  # 记录全部顶点
        self.color = None
    # 绘制
    def draw(self):
        if self.body == None or self.body == []:
            return
        for point in self.body:
            pygame.draw.rect(screen, self.color,(point[0], point[1], cellSize, cellSize))
    # 随机产生
    def born(self):
        self.body = []
        while True:
            x = cellSize*random.randint(3, windowWidth/cellSize-3)
            y = cellSize*random.randint(3, windowHeight/cellSize-3)
            if not checkOverlapping([x,y]):
                AllVar.allPoints.append([x,y])
                self.body.append([x, y])
                return

# 普通苹果
class Apple(GameProps):
    def __init__(self):
        self.color = Color(158, 46, 36)
    
        
# 苹果变大道具
class AppleBig(GameProps):
    def __init__(self):
        self.color = Color(65, 138, 180) 

# 变长道具
class Long(GameProps):
    def __init__(self):
        self.color = Color(0, 0, 0)
        
# 四周变墙道具
class AddWall(GameProps):
    def __init__(self):
        self.color = Color(153, 61, 15)
# 墙
class Wall(GameProps):
    def __init__(self):
        self.color = Color(153, 61, 15)
    def born(self):
        self.body = []


# 各种工具方法
# 绘制网格
def drawGrid():
    for i in range(cellSize, windowWidth, cellSize):
        pygame.draw.line(screen, (255, 255, 255), (i, 0), (i, windowHeight), 1)
    for j in range(cellSize, windowHeight, cellSize):
        pygame.draw.line(screen, (255, 255, 255), (0, j), (windowWidth, j), 1)

# 检查新点是否和已存在的点重叠
def checkOverlapping(newPoint):
    for point in AllVar.allPoints:
        if newPoint[0] == point[0] and newPoint[1] == point[1]:
            return True
    return False

# 新得到5分则随机添加一堵墙
def addRandomWall():
    if AllVar.score // 5 > AllVar.level: # 升级
        # 随机产生墙
        x = cellSize*random.randint(3, windowWidth/cellSize-3)
        y = cellSize*random.randint(3, windowHeight/cellSize-3)
        if not checkOverlapping([x,y]):
            AllVar.wall.body.append([x,y])
            AllVar.allPoints.append([x,y])
        
    
# 创建全局变量类
class AllVar():
    snake = None
    apple = None
    long   = None
    appleBig=None
    addWall = None
    wall = None
    state = ''
    allPoints = []
    score = 0
    level = 0

# 创建全部变量
AllVar.snake = Snack()
AllVar.apple = Apple()
AllVar.long  = Long()
AllVar.appleBig = AppleBig()
AllVar.addWall = AddWall()
AllVar.wall = Wall()
AllVar.state = 'start'

# 初始化游戏
def initGame():
    # 全部变量随机产生
    AllVar.snake.born()
    AllVar.apple.born()
    AllVar.long.born()
    AllVar.appleBig.born()
    AllVar.addWall.born()
    AllVar.wall.born()
    


# 开始界面显示文字
def drawText(state, words):
    fontObj1 = pygame.font.Font('freesansbold.ttf', 60)
    textSurfaceObj1 = fontObj1.render(state, True, (218, 227, 230))
    textRectObj1 = textSurfaceObj1.get_rect()
    textRectObj1.center = (windowWidth/2, windowHeight/3)
    screen.blit(textSurfaceObj1, textRectObj1)
    fontObj2 = pygame.font.Font('freesansbold.ttf', 30)
    textSurfaceObj2 = fontObj2.render(
        words, True, (218, 227, 230))
    textRectObj2 = textSurfaceObj2.get_rect()
    textRectObj2.center = (windowWidth/2, windowHeight*2/3)
    screen.blit(textSurfaceObj2, textRectObj2)

# 绘制全部对象
def paintAll():
    screen.fill([129, 216, 208])
    drawGrid()
    AllVar.snake.draw()
    AllVar.apple.draw()
    AllVar.long.draw()
    AllVar.appleBig.draw()
    AllVar.addWall.draw()
    AllVar.wall.draw()

# 移动全部对象
def moveAll():
    AllVar.snake.move()


# 游戏流程控制
def controlState():
    if AllVar.state == 'start':
        screen.fill([129, 216, 208])
        drawText('Snack', 'Arrow Button Start Game')
        handleEvent()
    elif AllVar.state == 'running':
        paintAll()
        moveAll()
        handleEvent()
    elif AllVar.state == 'end':
        screen.fill([129, 216, 208])
        long = str(len(AllVar.snake.body))
        drawText('Game Over', 'Your Score:'+ str(AllVar.score))
        handleEvent()
        

# 控制贪吃蛇，处理交互逻辑
def handleEvent():
    for event in pygame.event.get():
        # 监听退出操作
        if event.type == QUIT or event.type == KEYDOWN and event.key == K_ESCAPE:
            pygame.quit()
            sys.exit(-1)
        # 键盘控制贪吃蛇移动
        if event.type == KEYDOWN:
            if AllVar.state == 'start':
                AllVar.state = 'running'
                initGame()  # 游戏初始化
            if event.key == K_UP:
                AllVar.snake.turn(0)
            elif event.key == K_DOWN:
                AllVar.snake.turn(3)
            elif event.key == K_LEFT:
                AllVar.snake.turn(1)
            elif event.key == K_RIGHT:
                AllVar.snake.turn(2)
            elif AllVar.state == 'end' and event.key == K_r:
                initGame()
                AllVar.state = 'start'


# 游戏循环 -> 意味着游戏的正式开始！
while True:
    # 通过时钟对象指定循环频率，每秒循环X次
    clock.tick(8+AllVar.level)
    controlState()
    pygame.display.update()